#include "../pch.h"
#include "core/REFNameTable.h"
#include "core/REFXMLNameTable.h"
#include "schema/REFXMLSchemaInfo.h"
#include "REFXMLLoader.h"
#include "REFXMLElementList.h"
#include "schema/REFXMLSchemaElementDecl.h"
#include "schema/REFXMLSchemaDecl.h"

namespace BFX
{

REFXMLDocument::REFXMLDocument()
{
	m_pLastChild = NULL;
	m_pNameTable = new REFHashNameTable();
	m_pNameTable->AddRef();
	m_pDomNameTable = new REFXMLNameTable(this);
	m_pDomNameTable->AddRef();

	m_pElementIDAttrDecl = NULL;
	m_pSchemaInfo	= NULL;

	m_bPreserveWhitespace = false;
	m_bIsLoading = false;

	// force the following string instances to be default in the nametable
	m_strEmpty		= m_pNameTable->Add(UniString());
	m_strDocumentName	= m_pNameTable->Add(USTR("#document"));
	m_strDocumentFragmentName	= m_pNameTable->Add(USTR("#document-fragment"));
	m_strCommentName	= m_pNameTable->Add(USTR("#comment"));
	m_strTextName	= m_pNameTable->Add(USTR("#text"));
	m_strCDataSectionName	= m_pNameTable->Add(USTR("#cdata-section"));
	m_strEntityName	= m_pNameTable->Add(USTR("#entity"));
	m_strID			= m_pNameTable->Add(USTR("id"));
	m_strNonSignificantWhitespaceName	= m_pNameTable->Add(USTR("#whitespace"));
	m_strSignificantWhitespaceName	= m_pNameTable->Add(USTR("#significant-whitespace"));
	m_strXmlns		= m_pNameTable->Add(USTR("xmlns"));
	m_strXml		= m_pNameTable->Add(USTR("xml"));
	m_strSpace		= m_pNameTable->Add(USTR("space"));
	m_strLang		= m_pNameTable->Add(USTR("lang"));
	m_strReservedXmlns	= m_pNameTable->Add(USTR("http://www.w3.org/2000/xmlns/"));
	m_strReservedXml	= m_pNameTable->Add(USTR("http://www.w3.org/XML/1998/namespace"));

	m_bCDataNodesPresent = false;
	m_bEntRefNodesPresent = false;

	m_nChangeCount = 0;
}

REFXMLDocument::~REFXMLDocument()
{
	m_pDomNameTable->Release();
	m_pNameTable->Release();
	if (m_pElementIDAttrDecl != NULL)
		m_pElementIDAttrDecl->Release();
	if (m_pSchemaInfo != NULL)
		m_pSchemaInfo->Release();
}

XMLNodeType REFXMLDocument::GetNodeType() const
{
	return XMLNodeType_Document;
}

REFXMLNode* REFXMLDocument::GetParentNode() const
{
	return NULL;
}

UniString REFXMLDocument::GetName() const
{
	return m_strDocumentName;
}

UniString REFXMLDocument::GetLocalName() const
{
	return m_strDocumentName;
}

REFXMLDocument* REFXMLDocument::GetOwnerDocument() const
{
	return NULL;
}

// Returns an XmlNodeList containing
// a list of all descendant elements that match the specified name.
REFXMLNodeList* REFXMLDocument::GetElementsByTagName(const UniString& strName) const
{
	REFXMLNodeList* pNodeList = new REFXMLElementList(const_cast<REFXMLDocument*>(this), strName);
	pNodeList->Autorelease();
	return pNodeList;
}

// Returns the XmlElement with the specified ID.
REFXMLElement* REFXMLDocument::GetElementById(const UniString& strElementId) const
{
	if (m_pElementIdMap != NULL)
	{
		REF<REFXMLElementWeakRefArray> pElementList;
		if (m_pElementIdMap->Lookup(strElementId, pElementList))
		{
			for (int i = 0; i < pElementList->GetSize(); i ++)
			{
				REFXMLElement* pElem = pElementList->GetAt(i);
				if (pElem->IsConnected())
					return pElem;
			}
		}
	}
	return NULL;
}

// Returns a XmlNodeList containing
// a list of all descendant elements that match the specified localName with namespaceURI.
REFXMLNodeList* REFXMLDocument::GetElementsByTagName(const UniString& strLocalName, const UniString& strNamespaceURI) const
{
	REFXMLNodeList* pNodeList = new REFXMLElementList(const_cast<REFXMLDocument*>(this), strLocalName, strNamespaceURI);
	pNodeList->Autorelease();
	return pNodeList;
}

const XMLErrorContext& REFXMLDocument::GetLastError() const
{
	return m_errorContext;
}

bool REFXMLDocument::IsErrorOccurred() const
{
	return m_errorContext.IsErrorOccurred();
}

bool REFXMLDocument::IsContainer() const
{
	return true;
}

bool REFXMLDocument::IsValidChildType(XMLNodeType type) const
{
	switch ( type ) {
	case XMLNodeType_ProcessingInstruction:
	case XMLNodeType_Comment:
	case XMLNodeType_Whitespace:
	case XMLNodeType_SignificantWhitespace:
		return true;

	case XMLNodeType_DocumentType:
		// TODO: validate first.
		return true;

	case XMLNodeType_Element:
		BFX_ENSURE1 (GetDocumentElement() == NULL, "This document already has a 'DocumentElement' node.");
		return true;

	case XMLNodeType_XmlDeclaration:
		BFX_ENSURE1 (GetDeclaration() == NULL, "This document already has an 'XmlDeclaration' node.");
		// TODO: validate first.
		return true;

	default:
		return false;
	}
}

REFXMLLinkedNode* REFXMLDocument::GetFirstNode() const
{
	return m_pFirstChild;
}

void REFXMLDocument::SetFirstNode(REFXMLLinkedNode* pNode)
{
	m_pFirstChild = pNode;
}

REFXMLLinkedNode* REFXMLDocument::GetLastNode() const
{
	return m_pLastChild;
}

void REFXMLDocument::SetLastNode(REFXMLLinkedNode* pNode)
{
	m_pLastChild = pNode;
}

// Gets the root XmlElement for the document.
REFXMLElement* REFXMLDocument::GetDocumentElement() const
{
	return (REFXMLElement*)FindChild(XMLNodeType_Element);
}

// Creates an XmlAttribute with the specified name.
REFXMLAttribute* REFXMLDocument::CreateAttribute(const UniString& strName)
{
	UniString strPrefix;
	UniString strLocalName;
	UniString strNamespaceURI;

	SplitName(strName, strPrefix, strLocalName);
	SetDefaultNamespace(strPrefix, strLocalName, strNamespaceURI);
	return CreateAttribute(strPrefix, strLocalName, strNamespaceURI);
}

// Creates a XmlAttribute with the specified Prefix, LocalName, and NamespaceURI.
REFXMLAttribute* REFXMLDocument::CreateAttribute(const UniString& strPrefix, const UniString& strLocalName, const UniString& strNamespaceURI)
{
	REFXMLAttribute* pNewAttr = new REFXMLAttribute(AddAttrXmlName(strPrefix, strLocalName, strNamespaceURI), this);
	pNewAttr->Autorelease();
	return pNewAttr;
}
REFXMLAttribute* REFXMLDocument::CreateDefaultAttribute(const UniString& strPrefix, const UniString& strLocalName, const UniString& strNamespaceURI)
{
	REFXMLAttribute* pNewAttr = new REFXMLUnspecifiedAttribute(strPrefix, strLocalName, strNamespaceURI, this);
	pNewAttr->Autorelease();
	return pNewAttr;
}
// Creates an element with the specified name.
REFXMLElement* REFXMLDocument::CreateElement(const UniString& strName)
{
	UniString strPrefix;
	UniString strLocalName;

	SplitName(strName, strPrefix, strLocalName);
	return CreateElement(strPrefix, strLocalName, m_strEmpty);
}

// Creates a XmlDocument with the specified Prefix, LocalName, and NamespaceURI.
REFXMLElement* REFXMLDocument::CreateElement(const UniString& strPrefix, const UniString& strLocalName, const UniString& strNamespaceURI)
{
	REFXMLElement* pNewElem = new REFXMLElement(AddXmlName(strPrefix, strLocalName, strNamespaceURI), this);
	pNewElem->Autorelease();
	return pNewElem;
}

// Creates an XmlText with the specified text.
REFXMLText* REFXMLDocument::CreateTextNode(const UniString& strText)
{
	REFXMLText* pNewText = new REFXMLText(strText, this);
	pNewText->Autorelease();
	return pNewText;
}

// Creates a XmlCDataSection containing the specified data.
REFXMLCDataSection* REFXMLDocument::CreateCDataSection(const UniString& strData)
{
    REFXMLCDataSection* pNewCData = new REFXMLCDataSection(strData, this);
	pNewCData->Autorelease();

    m_bCDataNodesPresent = true;
	return pNewCData;
}

// Creates an XmlComment containing the specified data.
REFXMLComment* REFXMLDocument::CreateComment(const UniString& strData)
{
	REFXMLComment* pNewComm = new REFXMLComment(strData, this);
	pNewComm->Autorelease();
	return pNewComm;
}

// Returns a new XmlDocumentType object.
REFXMLDocumentType* REFXMLDocument::CreateDocumentType(const UniString& strName, const UniString& strPublicId, const UniString& strSystemId, const UniString& strInternalSubset)
{
	REFXMLDocumentType* pDocType = new REFXMLDocumentType(strName, strPublicId, strSystemId, strInternalSubset, this);
	pDocType->Autorelease();
	return pDocType;
}

// Creates a XmlProcessingInstruction with the specified name and data strings.
REFXMLProcessingInstruction* REFXMLDocument::CreateProcessingInstruction(const UniString& strTarget, const UniString& strData)
{
	REFXMLProcessingInstruction* pNewPI = new REFXMLProcessingInstruction(strTarget, strData, this);
	pNewPI->Autorelease();
	return pNewPI;
}

// Creates a XmlDeclaration node with the specified values.
REFXMLDeclaration* REFXMLDocument::CreateXmlDeclaration(const UniString& strVersion, const UniString& strEncoding, const UniString& strStandalone)
{
	REFXMLDeclaration* pDecl = new REFXMLDeclaration(strVersion, strEncoding, strStandalone, this);
	pDecl->Autorelease();
	return pDecl;
}

// Creates an XmlEntityReference with the specified name.
REFXMLEntityReference* REFXMLDocument::CreateEntityReference(const UniString& strName)
{
	REFXMLEntityReference* pNewEntRef = new REFXMLEntityReference(strName, this);
	pNewEntRef->Autorelease();

	m_bEntRefNodesPresent = true;
	return pNewEntRef;
}

UniString REFXMLDocument::GetInnerXml() const
{
	return REFXMLNode::GetInnerXml();
}

void REFXMLDocument::SetInnerXml(const UniString& str)
{
	LoadXml(str);
}

UniString REFXMLDocument::GetBaseURI() const
{
	return m_strBaseURI;
}

// Saves the node to the specified XmlWriter.
// 
//Writes out the to the file with exact content in the xmldocument.
void REFXMLDocument::WriteTo(REFXMLWriter* w) const
{
	WriteContentTo(w);
}

// Saves all the children of the node to the specified XmlWriter.
// 
//Writes out the to the file with exact content in the XmlDocument.
void REFXMLDocument::WriteContentTo(REFXMLWriter* w) const
{
	for (REFXMLNode* n = GetFirstChild(); n != NULL; n = n->GetNextSibling())
	{
		n->WriteTo(w);
	}
}

// Saves the XML document to the specified XmlWriter.
// 
//Saves out the file with xmldeclaration which has encoding value equal to that of textwriter's encoding
void REFXMLDocument::Save(REFXMLWriter* w)
{
	REFXMLNode* n = GetFirstChild();
	if (n == NULL)
		return;
	if (w->GetWriteState() == REFXMLWriter::WriteStateStart)
	{
		if (n->GetNodeType() == XMLNodeType_XmlDeclaration)
		{
			if (GetStandalone() == USTR("yes"))
				w->WriteStartDocument(true);
			else if (GetStandalone() == USTR("no"))
				w->WriteStartDocument(false);
			else
				w->WriteStartDocument();

			n = n->GetNextSibling();
		}
		else
		{
			w->WriteStartDocument();
		}
		w->WriteStartDocument();
	}
	while (n != NULL)
	{
		n->WriteTo(w);
		n = n->GetNextSibling();
	}
	w->Flush();
}

// Loads the XML document from the specified xmlreader.
bool REFXMLDocument::Load(REFXMLReader* r)
{
	m_bIsLoading = true;
	RemoveAll();
	m_bCDataNodesPresent = false;
	m_bEntRefNodesPresent = false;
	REF<REFXMLLoader> pLoader = new REFXMLLoader();
	bool bSuccess = pLoader->Load(this, r, m_bPreserveWhitespace);
	m_errorContext = r->GetLastError();

	m_bIsLoading = false;
	return bSuccess;
}

// Loads the XML document from the specified string.
bool REFXMLDocument::LoadXml(const UniString& strXml)
{
	REF<REFXMLTextReader> pReader = new REFXMLTextReader(new REFUniStringReader(strXml), GetNameTable());
	pReader->SetEntityHandling(XMLEntityHandling_ExpandCharEntities);
	// TODO: More settings...
	
	bool bSuccess = Load(pReader);
	pReader->Close();

	return bSuccess;
}

void REFXMLDocument::SetBaseURI(const UniString& strBaseURI)
{
	m_strBaseURI = strBaseURI;
}

REFXMLNodeMap* REFXMLDocument::GetEntities() const
{
	if (m_pEntities == NULL)
	{
		REFXMLDocument* pThis = const_cast<REFXMLDocument*>(this);
		pThis->m_pEntities = new REFXMLNodeMap(pThis);
	}
	return m_pEntities;
}

void REFXMLDocument::SetEntities(REFXMLNodeMap* pEntities)
{
	m_pEntities = pEntities;
}

REFXMLSchemaInfo* REFXMLDocument::GetDtdSchemaInfo() const
{
	return m_pSchemaInfo;
}

void REFXMLDocument::SetDtdSchemaInfo(REFXMLSchemaInfo* pSchemaInfo)
{
	if (m_pSchemaInfo != NULL)
		m_pSchemaInfo->Release();

	m_pSchemaInfo = pSchemaInfo;

	if (m_pSchemaInfo != NULL)
		m_pSchemaInfo->AddRef();
}

REFXMLName* REFXMLDocument::AddXmlName(const UniString& strPrefix, const UniString& strLocalName, const UniString& strNamespaceURI)
{
	return m_pDomNameTable->AddName(strPrefix, strLocalName, strNamespaceURI);
}

REFNameTable* REFXMLDocument::GetNameTable() const
{
	return m_pNameTable;
}

UniString REFXMLDocument::GetStandalone() const
{
	REFXMLDeclaration* pDecl = GetDeclaration();
	if (pDecl != NULL)
		return pDecl->GetStandalone();
	return UniString();	// empty
}

REFXMLDeclaration* REFXMLDocument::GetDeclaration() const
{
	REFXMLNode* pNode = GetFirstChild();
	if (pNode != NULL)
	{
		if (pNode->GetNodeType() == XMLNodeType_XmlDeclaration)
			return (REFXMLDeclaration*)pNode;
	}
	return NULL;
}

// Gets the node for the DOCTYPE declaration.
REFXMLDocumentType* REFXMLDocument::GetDocumentType() const
{
	return(REFXMLDocumentType*)FindChild(XMLNodeType_DocumentType);
}

REFXMLEntity* REFXMLDocument::GetEntityNode(const UniString& strName)
{
	if (GetDocumentType() != NULL)
	{
		REFXMLNodeMap* pEntities = GetDocumentType()->GetEntities();
		if (pEntities != NULL)
			return (REFXMLEntity*)pEntities->GetNamedItem(strName);
	}
	return NULL;
}

void REFXMLDocument::SetDefaultNamespace(const UniString& strPrefix, const UniString& strLocalName, OUT UniString& strNamespaceURI)
{
	if (strPrefix == m_strXmlns || (strPrefix.GetLength() == 0 && strLocalName == m_strXmlns))
	{
		strNamespaceURI = m_strReservedXmlns;
	}
	else if (strPrefix == m_strXml)
	{
		strNamespaceURI = m_strReservedXml;
	}
}

REFXMLName* REFXMLDocument::AddAttrXmlName(const UniString& strPrefix, const UniString& strLocalName, const UniString& strNamespaceURI)
{
	return AddXmlName(strPrefix, strLocalName, strNamespaceURI);
}

REFXMLName* REFXMLDocument::GetXmlName(const UniString& strPrefix, const UniString& strLocalName, const UniString& strNamespaceURI)
{
	return m_pDomNameTable->GetName(strPrefix, strLocalName, strNamespaceURI);
}

bool REFXMLDocument::AddElementIdInfo(REFXMLName* pEleName, REFXMLName* pAttrName)
{
	//when XmlLoader call XmlDocument.AddInfo, the element.XmlName and attr.XmlName 
	//have already been replaced with the ones that don't have namespace values (or just
	//string.Empty) because in DTD, the namespace is not supported
	if (m_pElementIDAttrDecl == NULL || m_pElementIDAttrDecl->Contains(pEleName))
	{
		if (m_pElementIDAttrDecl == NULL)
		{
			m_pElementIDAttrDecl = new REFXMLElementIDAttrDeclMap();
			m_pElementIDAttrDecl->AddRef();
		}
		m_pElementIDAttrDecl->Set(pEleName, pAttrName);
		return true;
	}
	return false;
}

REFXMLName* REFXMLDocument::GetElementIdInfo(REFXMLName* pEleName)
{
	// When XmlDocument is getting the IDAttribute for a given element, 
	// we need only compare the prefix and localname of element.XmlName with the registered m_pElementIDAttrDecl.
	if (m_pElementIDAttrDecl != NULL)
	{
		REFXMLName* pNewName = GetXmlName(pEleName->GetPrefix(), pEleName->GetLocalName(), UniString()/*, NULL*/);
		if (pNewName != NULL)
		{
			REFXMLElementIDAttrDeclMap::POSITION entry = m_pElementIDAttrDecl->LookupEntry(pNewName);
			return entry == NULL ? NULL : entry->value;
		}
	}
	return NULL;
}

REFXMLElement* REFXMLDocument::GetElement(REFXMLElementWeakRefArray* pElementList, REFXMLElement* pElem)
{
	BFX_ASSERT(pElementList != NULL);
	BFX_ASSERT(pElem != NULL);

	REF<REFXMLElementWeakRefArray> pGarbageList = new REFXMLElementWeakRefArray();
	for (int i = 0; i < pElementList->GetSize(); i ++)
	{
		REFXMLElement* pElem1 = pElementList->GetAt(i);
		if (!pElem1->IsConnected())	// NOTE: maybe we need to check the owner document.
		{
			pGarbageList->Add(pElem1);
		}
		else if (pElem1 == pElem)
		{
			return pElem1;
		}
	}
	// clear out the garbage elements
	for (int i = 0; i < pGarbageList->GetSize(); i ++)
	{
		REFXMLElement* pElem2 = pGarbageList->GetAt(i);
		pElementList->Remove(pElem2);
	}
	return NULL;
}

void REFXMLDocument::AddElementWithId(const UniString& strId, REFXMLElement* pElem)
{
	REF<REFXMLElementWeakRefArray> pElementList;
	if (m_pElementIdMap == NULL || !m_pElementIdMap->Lookup(strId, pElementList))
	{
		if (m_pElementIdMap == NULL)
			m_pElementIdMap = new REFXMLElementIdMap();
		pElementList = new REFXMLElementWeakRefArray();
		pElementList->Add(pElem);
		m_pElementIdMap->Set(strId, pElementList);
	}
	else
	{
		// there are other element(s) that has the same id
		if (GetElement(pElementList, pElem) == NULL)
			pElementList->Add(pElem);
	}
}

void REFXMLDocument::RemoveElementWithId(const UniString& strId, REFXMLElement* pElem)
{
	REF<REFXMLElementWeakRefArray> pElementList;
	if (m_pElementIdMap != NULL && m_pElementIdMap->Lookup(strId, pElementList))
	{
		REFXMLElement* pOldElem = GetElement(pElementList, pElem);
		if (pOldElem != NULL)
		{
			pElementList->Remove(pOldElem);
			if (pElementList->GetSize() == 0)
				m_pElementIdMap->Remove(strId);
		}
	}
}

REFXMLNode* REFXMLDocument::AppendChildForLoad(REFXMLNode* pNewChild, REFXMLDocument* pDoc)
{
	BFX_ASSERT (pDoc == this);
	BFX_ENSURE1 (IsValidChildType(pNewChild->GetNodeType()), "The specified node cannot be inserted as the valid child of this node, because the specified node is the wrong type.");

	REFXMLLinkedNode* pNewNode = (REFXMLLinkedNode*) pNewChild;
	if (m_pLastChild == NULL)
	{
		BFX_ASSERT(m_pFirstChild == NULL);
		m_pFirstChild = m_pLastChild = pNewNode;
	}
	else
	{
		REFXMLLinkedNode* pRefNode = m_pLastChild;
		pNewNode->m_pPrev = pRefNode;
		pRefNode->m_pNext = pNewNode;
		m_pLastChild = pNewNode;
	}
	pNewNode->SetParentForLoad(this);

	pDoc->NotifyChanged();
	return pNewNode;
}

// The function such through schema info to find out if there exists a default attribute with passed in names in the passed in element
// If so, return the newly created default attribute (with children tree);
// Otherwise, return null.
REFXMLAttribute* REFXMLDocument::GetDefaultAttribute(REFXMLElement* pElem, const UniString& strAttrPrefix, const UniString& strAttrLocalname, const UniString& strAttrNamespaceURI)
{
	REFXMLSchemaInfo* pSchemaInfo = GetDtdSchemaInfo();
	REFXMLSchemaElementDecl* pElemDecl = GetSchemaElementDecl(pElem);
	if (pElemDecl != NULL && pElemDecl->GetAttDefs() != NULL)
	{
		for (REFXMLSchemaAttDefMap::POSITION entry = pElemDecl->GetAttDefs()->GetFirstEntry(); entry != NULL; entry = pElemDecl->GetAttDefs()->GetNextEntry(entry))
		{
			REFXMLSchemaAttDef* pAttdef = entry->value;
			if (pAttdef->GetPresence() == REFXMLSchemaDecl::UseDefault || pAttdef->GetPresence() == REFXMLSchemaDecl::UseFixed)
			{
				if (pAttdef->GetName()->GetName() == strAttrLocalname)
				{
					if ((pSchemaInfo->GetSchemaType() == REFXMLSchemaDecl::SchemaTypeDTD && pAttdef->GetName()->GetNamespace() == strAttrPrefix) ||
						(pSchemaInfo->GetSchemaType() != REFXMLSchemaDecl::SchemaTypeDTD && pAttdef->GetName()->GetNamespace() == strAttrNamespaceURI))
					{
						// find a def attribute with the same name, build a default attribute and return
						REFXMLAttribute* pDefattr = PrepareDefaultAttribute(pAttdef, strAttrPrefix, strAttrLocalname, strAttrNamespaceURI);
						return pDefattr;
					}
				}
			}
		}
	}
	return NULL;
}

REFXMLSchemaElementDecl* REFXMLDocument::GetSchemaElementDecl(REFXMLElement* pElem)
{
    REFXMLSchemaInfo* pSchemaInfo = GetDtdSchemaInfo();
    if (pSchemaInfo != NULL)
	{
        // build XmlQualifiedName used to identify the element schema declaration
		REFXMLQualifiedName* pQName = new REFXMLQualifiedName(pElem->GetLocalName(), pSchemaInfo->GetSchemaType() == REFXMLSchemaDecl::SchemaTypeDTD ? pElem->GetPrefix() : pElem->GetNamespaceURI());
        //get the schema info for the element
		REF<REFXMLSchemaElementDecl> pElemDecl;
		pSchemaInfo->GetElementDecls()->Lookup(pQName, pElemDecl);
		return pElemDecl;
    }
    return NULL;
}

// Will be used by AddDeafulatAttributes() and GetDefaultAttribute() methods
REFXMLAttribute* REFXMLDocument::PrepareDefaultAttribute(REFXMLSchemaAttDef* pAttdef, const UniString& strAttrPrefix, const UniString& strAttrLocalname, const UniString& strAttrNamespaceURI)
{
	UniString strAttrNamespaceURI2 = strAttrNamespaceURI;
	SetDefaultNamespace(strAttrPrefix, strAttrLocalname, INOUT strAttrNamespaceURI2);
	REFXMLAttribute* pDefattr = CreateDefaultAttribute(strAttrPrefix, strAttrLocalname, strAttrNamespaceURI);
	// parsing the default value for the default attribute
	pDefattr->SetInnerXml(pAttdef->GetDefaultValueRaw());
	// during the expansion of the tree, the flag could be set to true, we need to set it back.
	REFXMLUnspecifiedAttribute* pUnspAttr = (REFXMLUnspecifiedAttribute*)pDefattr;
	pUnspAttr->SetSpecified(false);

	return pDefattr;
}

void REFXMLDocument::NotifyChanged()
{
	m_nChangeCount++;
}

int REFXMLDocument::GetChangeCount() const
{
	return m_nChangeCount;
}

}	//	namespace BFX
